layui.define(['form', 'laydate', 'laytpl'], function (exports) {
  "use strict";

  var $ = layui.$,
    laytpl = layui.laytpl,
    laydate = layui.laydate,

    //模块名
    MOD_NAME = 'filterContainer', 
    //外部接口
    filterContainer = {
      config: {}, 
      
      index: layui[MOD_NAME] ? (layui[MOD_NAME].index + 10000) : 0, 

      //设置全局项
      set: function (options) {
        var that = this;
        that.config = $.extend({}, that.config, options);
        return that;
      }, 

      //事件监听
      on: function (events, callback) {
        return layui.onevent.call(this, MOD_NAME, events, callback);
      }
    }, 

    NONE = 'filter-none',
    //主模板
    TPL_MAIN = `<div class="filter-container"></div>`, 

    // 子模板
    TPL_GROUP = `<div class="filter-container-group"></div>`, 

    // 模板
    TPL_ITEM = `<div class="filter-container-item">
      <div class="filter-container-label">{{= d.title }}：</div>
      <div class="filter-container-content">
        <div class="filter-container-value">
          
        </div>
        {{# if(d.attr.isMulti){ }}
          <div class="filter-container-multi">
            <button type="button" class="layui-btn layui-btn-primary layui-btn-xs diy-form-add" style="background-color: white;">
              <i class="layui-icon layui-icon-add-1"></i> 多选
            </button>
          </div>
        {{# } }}
        
      </div>
    </div>`,

    // 确定按钮
    TPL_CONFIRM = `<button type="button" class="layui-btn layui-btn-normal layui-btn-sm filter-container-confirm" style="width: 80px;">确定</button>`,

    // 取消按钮
    TPL_CANCEL = `<button type="button" class="layui-btn layui-btn-normal layui-btn-sm filter-container-cancel" style="color: #54668b;
      background-color: white; width: 80px; margin-right: 26px;">取消</button>`,


    //操作当前实例
    thisModule = function () {
      var that = this
        , options = that.config
        , id = options.id || that.index;

      thisModule.that[id] = that; //记录当前实例对象
      thisModule.config[id] = options; //记录当前实例配置项

      return {
        config: options,
        //重置实例
        reload: function (options) {
          that.reload.call(that, options);
        },
        getData: function () {
          return that.getData.call(that);
        },
      }
    },
    //构造器
    Class = function (options) {
      var that = this;
      that.index = ++filterContainer.index;
      that.config = $.extend({}, that.config, filterContainer.config, options);
      that.render();
    };

    //默认配置
    Class.prototype.config = {
      isMultiSelectOpen: false,
    };


    //重载实例
    Class.prototype.reload = function (options) {
      var that = this;
      that.config = $.extend(true, {}, that.config, options);
      that.render();
    };

    //渲染
    Class.prototype.render = async function () {
      var that = this
        , options = that.config;
        
      //解析模板
      var othis = options.elem = $(options.elem);
      if (!othis[0]) return;

      // 获取数据
      await that.pullData();

      // 生成组件结构
      const filterContainer = that.create();

      //插入组件结构
      othis.html(filterContainer)

      // 渲染时间控件
      that.renderDate();
      
      that.events(); //事件

      // 加载完成回调
      typeof options.done === 'function' && options.done();
    };

    // 获取数据
    Class.prototype.pullData = function () {
      var that = this,
        e = that.elem,
        options = that.config;
      var data = [];
        return new Promise((resolve, reject) => {
        if(options.url){ // Ajax请求
          $.ajax({
            type: options.method || 'get'
            ,url: options.url
            ,contentType: options.contentType
            ,data: options.params
            ,dataType: options.dataType || 'json'
            ,jsonpCallback: options.jsonpCallback
            ,headers: options.headers || {}
            ,success: function(res){
              const data = res.data || [];
              if (data.length == 0) {
                that.errorView('请求异常，错误提示：'+ res.msg || '数据为空');
                return;
              }
              resolve(data);
              options.data = data;
            }
            ,error: function(e, msg){
              that.errorView('请求异常，错误提示：'+ msg || '数据为空');
            }
          });
        }else{ // 本地数据
          data = options.data;
          resolve(data);
        }
      })
    };

    // 异常提示
  Class.prototype.errorView = function(html){
    var that = this
    ,layNone = $('<div class="'+ NONE +'" style="line-height: 26px; padding: 30px 15px; text-align: center; color: #999; ">'+ (html || 'Error') +'</div>');

    that.config.elem.html(that.layNone = layNone);
  };

    // 生成模板
    Class.prototype.create = function () {
      var that = this,
        e = that.elem,
        a = that.config;
      const main = $(TPL_MAIN);
      
      for (let index = 0; index < a.data.length; index++) {
        const group = $(TPL_GROUP);
        const element = a.data[index];
        const item = $(laytpl(TPL_ITEM).render(element));
        const valueDom = item.find('.filter-container-value');
        // 生成模板value
        that.createValue(valueDom, element);
        group.append(item);
        main.append(group);
      }
      return main;
    };

    // 生成模板value
    Class.prototype.createValue = function (valueDom, data) {
      var that = this,
        e = that.elem,
        a = that.config;
      for (let index = 0; index < data.options.length; index++) {
        const element = data.options[index];
        // enum
        if (data.type === 'enum') {
          const value = $(`<div>${element.caption}</div>`);
          value.attr('value', element.value);
          
          if ((data.defaultValues && data.defaultValues.indexOf(element.value) > -1) || index === 0) {
            valueDom.find('div').eq(0).removeClass('filter-container-value-selected');
            value.addClass('filter-container-value-selected');
            const defaultValues = Array.isArray(data.defaultValues) ? data.defaultValues : [data.defaultValues || ''];
            // 设置默认值
            let odata = a.data.find(el => el.field === data.field);
            odata.value = defaultValues;
          }
          valueDom.append(value);
        } else if (data.type === 'date') {
          // date
          const value = $(`<div >${element.caption}</div>`);
          if ((data.defaultValues && data.defaultValues.indexOf(element.value) > -1) || index === 0) {
            // 移除第一个div默认值
            valueDom.find('div').eq(0).removeClass('filter-container-value-selected');
            value.addClass('filter-container-value-selected');
            const defaultValues = Array.isArray(data.defaultValues) ? data.defaultValues : [data.defaultValues || ''];
            // 设置默认值
            let odata = a.data.find(el => el.field === data.field);
            odata.value = defaultValues;
          }
          valueDom.append(value);
        }
      }

      // 自定义
      if (data.type === 'date' && data.attr.isCustom) {
        // date
        const placeholder = data.placeholder || 'yyyy-MM-dd';
        const dateInput = $(`<span class="_1jxEsDq-">自定义</span> <div class="filter-container-value-unselect">
          <i class="layui-icon layui-icon-date" style="position: absolute; padding: 10px;"></i> 
          <input type="text" name="${data.field}" id="${data.field}" lay-verify="date" placeholder="${placeholder}"
          autocomplete="off" class="layui-input" style="width: 212px;padding-left: 30px;"></input></div>`)
        valueDom.append(dateInput);
      }

      return valueDom;
    };  

    // 渲染时间控件
    Class.prototype.renderDate = function () {
      var that = this,
        e = that.elem,
        options = that.config;
      for (let index = 0; index < options.data.length; index++) {
        const element = options.data[index];
        if (element.type === 'date') {
          // 日期组件
          laydate.render({
            elem: `#${element.field}`,
            range: element.attr.range ?? false,
            rangeLinked: true,
            done: function (value, date, endDate) {
              // 清空，默认选中第一个
              const group = $(this.elem).parents('.filter-container-group');
              const index = group.index();
              if (value === '') {
                const obj = group.find('.filter-container-value div').eq(0);
                that.selectValue(obj);
                that.onSelect('selected');
                return false;
              }
              // 确认清空选中
              const selected = group.find('.filter-container-value-selected');
              selected.removeClass('filter-container-value-selected');
              const data = options.data[index];
              data.value = [value];
              that.onSelect('selected');
            }
          });
        }
      }
    };

    //事件
    Class.prototype.events = function () {
      var that = this,
        options = that.config;

      // select value 排除unselect
      $(options.elem).on('click', '.filter-container-value div:not(.filter-container-value-unselect)', function (e) {
        that.selectValue(this);
      });
        
      // multi
      $(options.elem).on('click', '.filter-container-multi', function (e) {
        // 获取item index
        const group = $(this).parents('.filter-container-group');
        const index = group.index();
        const data = options.data[index];
        options.isMultiSelectOpen = true;
        // 重新赋值data
        options.data[index] = data;
        $(this).hide();
        const item = $(`<div class="filter-container-item" style="justify-content: center; display: flex;"></div>`)
        item.append($(TPL_CANCEL)).append($(TPL_CONFIRM));
        group.append(item);
      });

      // confirm
      $(options.elem).on('click', '.filter-container-confirm', function (e) {
        // 获取item index
        const group = $(this).parents('.filter-container-group');
        const self = $(this).parents('.filter-container-item');
        const index = group.index();
        const data = options.data[index];
        // 获取选中项
        const selected = group.find('.filter-container-value-selected');
        const selectedValues = [];
        selected.each(function (index, element) {
          selectedValues.push(data.options[$(element).index()].value);
        });
        data.value = selectedValues;
        options.isMultiSelectOpen = false;
        group.find('.filter-container-multi').show();
        self.remove();
        that.onSelect('confirm');
      });

      // cancel
      $(options.elem).on('click', '.filter-container-cancel', function (e) {
        // 获取item index
        const group = $(this).parents('.filter-container-group');
        const self = $(this).parents('.filter-container-item');
        const index = self.index();
        options.isMultiSelectOpen = false;
        group.find('.filter-container-multi').show();
        self.remove();
        // 重置选中
        that.recoverSelected(index)
        that.onSelect('cancel');
      })
    };

    // 选中 value
    Class.prototype.selectValue = function (obj) {
      var that = this,
        options = that.config;
      const group = $(obj).parents('.filter-container-group');
      const item = $(obj).parents('.filter-container-item');
      const index = group.index();
      const data = options.data[index];
      const isMultiSelectOpen = options.isMultiSelectOpen || false;
      const value = data.options[$(obj).index()].value;
      // 获取当前是否选中
      const isSelected = $(obj).hasClass('filter-container-value-selected');
      if (isMultiSelectOpen) {
        if (!value) {
          // 单选
          $(obj).addClass('filter-container-value-selected').siblings().removeClass('filter-container-value-selected');
          options.selectedValues = [value];
          return false
        }
        // 多选
        $(obj).toggleClass('filter-container-value-selected');
        if (isSelected) {
          // 取消选中
          options.selectedValues.splice(options.selectedValues.indexOf(value), 1);
        } else {
          // 移除第一个选项
          item.find('.filter-container-value div:first-child').removeClass('filter-container-value-selected');
        }
      } else {
        // 单选
        $(obj).addClass('filter-container-value-selected').siblings().removeClass('filter-container-value-selected');
        data.value = [value];
        that.onSelect('selected');
      }
      // 重置时间
      if (data.type === 'date') {
        // 日期组件
        $(group).find(`#${data.field}`).val('');
      }
    };

    // 点击取消后，恢复选中
    Class.prototype.recoverSelected = function (index) {
      const { elem, data: optionsData } = this.config;
      const data = optionsData[index];
      const group = $(elem).find('.filter-container-group').eq(index);
      const item = group.find('.filter-container-item');

      let value = Array.isArray(data.value) ? data.value : [data.value || ''];

      if (!value.length) {
        // TODO: 兼容老的浏览器
        value[0] = (data.options[0] && data.options[0].value) ? data.options[0].value : '';
      }

      item.find('.filter-container-value div').removeClass('filter-container-value-selected');

      value.forEach(val => {
        const index = data.options.findIndex(item => item.value === val);
        item.find('.filter-container-value div').eq(index).addClass('filter-container-value-selected');
      });
    };

    // 获取数据
    Class.prototype.getData = function () {
      const { data: optionsData } = this.config;

      return optionsData.reduce((result, element) => {
        const { value = [], field, type } = element;
      
        if (!value.length || (value.length === 1 && !value[0])) return result;

        let condition = value.length > 1 ? 'in' : '=';
        let conditionValue = value.length > 1 ? value : value[0];

        if (type === 'date') condition = 'between';

        return [...result, {field, condition, value: conditionValue}];
      }, []);
    };

    // 选择回调
    Class.prototype.onSelect = function (type) {
      var that = this,
        options = that.config;
      // 回调
      typeof options.onSelect === 'function' && options.onSelect(type, that.getData());
    };


    //记录所有实例
    thisModule.that = {}; //记录所有实例对象
    thisModule.config = {}; //记录所有实例配置项
    
    //获取当前实例对象
    thisModule.getThis = function(id){
      var that = thisModule.that[id];
      if(!that) hint.error(id ? (MOD_NAME +' instance with ID \''+ id +'\' not found') : 'ID argument required');
      return that
    };
    
    //重载实例
    filterContainer.reload = function (id, options) {
      var that = thisModule.that[id];
      that.reload(options);
      return thisModule.call(that);
    };
    //核心入口
    filterContainer.render = function (options) {
      var inst = new Class(options);
      return thisModule.call(inst);
    };
    
    exports(MOD_NAME, filterContainer);
});